﻿namespace ExcelTool
{
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Reflection;
    using System.Text;
    using System.Threading.Tasks;

    public partial class Converter 
    {
        int cs_indent = 0;
        #region 解析类生成
        bool appendClassContentByType(StringBuilder result, XmlFieldEntry fe) {
            Reporter.RecordConverterInfo(fe);

            StringBuilder formatter = new StringBuilder();

            string count_str = string.Empty;
            if (fe.count_num> 1)
            {
                count_str = fe.count_num.ToString();
                if (fe.count_ref_const)
                {
                    count_str = string.Format("{0}.{1}", FormatHelper.MakeCSMetaName(fe.ParentSet.ParentLib), fe.count_str.ToUpper());     
                }
                formatter.Append("public List<{0}> {1} = new List<{0}>({2});");
            }
            else
            {
                formatter.Append("public {0} {1};");
            }

            //注释
            if (!string.IsNullOrEmpty(fe.desc))
            {
                formatter.AppendFormat("//{0}", fe.desc);
            }

            string type = string.Empty;
            if (XML_DATA_TYPE_NAME.IsBaseType(fe.type))
            {
                type = fe.type;
            }
            else
            {
                XmlBaseSet baseSet;
                if (!getReferenceConfig(fe, out baseSet)) return false;
                if (fe.type == XML_DATA_TYPE_NAME.ENUM)
                {
                    //type = XML_DATA_TYPE_NAME.INT;
                    type = FormatHelper.MakeCSEnumName(baseSet);
                }
                else if (fe.type == XML_DATA_TYPE_NAME.GROUP) {
                    type = FormatHelper.MakeGroupWrapperClass(baseSet as XmlGroupSet);
                }
                else
                {
                    type = FormatHelper.MakeCSSetName(baseSet as XmlBaseRefer);
                }
            }
            FormatHelper.CodeContent(result, 
                                     string.Format(formatter.ToString(), type, 
                                                   fe.Primary ? FILE_FORMAT.PRIMARY_NAME : fe.name, count_str), 
                                     cs_indent);
            return true;
        }
        bool _enumCsharpProcess(XmlBaseSet base_set, StringBuilder sb) {
            XmlEnumSet enum_set = base_set as XmlEnumSet;
            if(enum_set == null) {
                Reporter.PushError("内存数据转换异常 name : {0}", base_set.name);
                return false;
            }

            //CS
            FormatHelper.CodeContent(sb, string.Format("public enum {0} {{", FormatHelper.MakeCSEnumName(base_set)), cs_indent++);
            foreach(XmlEnumEntry entry in enum_set.EntryList) {
                Reporter.RecordConverterInfo(entry);
                FormatHelper.CodeContent(sb, string.Format("{0} = {1}, //{2}", entry.name, entry.value, entry.key), cs_indent);
            }

            FormatHelper.CodeRightBracket(sb, ref cs_indent);

            return true;
        }
        bool _baseElementCsharpProcess(XmlBaseRefer baseRefer, StringBuilder sb) {
            if (baseRefer.type == XML_DATA_TYPE_NAME.GROUP)
            {
                //Group类型标记需要加一个额外的类用于解析
                FormatHelper.CodeContent(sb, FILE_FORMAT.SERIALIZABLE, cs_indent);
                FormatHelper.CodeContent(sb, string.Format("public class {0}{{", FormatHelper.MakeGroupWrapperClass(baseRefer as XmlGroupSet)), cs_indent++);

                FormatHelper.CodeContent(sb, string.Format("public List<{0}> group = new List<{0}>();", FormatHelper.MakeCSSetName(baseRefer)), cs_indent);

                FormatHelper.CodeRightBracket(sb, ref cs_indent);
            }

            FormatHelper.CodeContent(sb, FILE_FORMAT.SERIALIZABLE, cs_indent);
            FormatHelper.CodeContent(sb, string.Format("public class {0}{{", FormatHelper.MakeCSSetName(baseRefer)), cs_indent++);
            for (int i = 0; i < baseRefer.fieldCfg.Count; i++)
            {
                XmlFieldEntry fe = baseRefer.fieldCfg[i];
                if(fe.mode == JSON_MODE.SERVER) {
                    continue;
                }
                if(!appendClassContentByType(sb, fe)) return false;
            }
            FormatHelper.CodeRightBracket(sb, ref cs_indent);

            return true;
        }
        bool processOneLib(XmlMetalib lib) {
            //根据已经载入的XML配置，写入数据，输出代码
            //const code
            StringBuilder cs_sb = new StringBuilder();
            StringBuilder enum_sb = new StringBuilder();
            StringBuilder class_sb = new StringBuilder();
            FormatHelper.CSharpHeader(cs_sb);

            FormatHelper.CodeContent(cs_sb, string.Format("public class {0}{{", FormatHelper.MakeCSMetaName(lib)), cs_indent++ );
            foreach (var const_it in lib.const_config)
            {
                FormatHelper.CodeContent(cs_sb, string.Format("public const int {0} = {1};", const_it.name.ToUpper(), const_it.value), cs_indent);
            }
            FormatHelper.CodeRightBracket(cs_sb, ref cs_indent);

            foreach (var item in lib.ReferenceSets)
            {
                XmlBaseSet ref_set = item.Value;
                if(ref_set.mode == JSON_MODE.SERVER) {
                    continue;
                }

                if (!XML_DATA_TYPE_NAME.CheckTypeValid(ref_set.type))
                {
                    Reporter.PushError("Type:{0} 非有效类型!", ref_set.type);
                    return false;
                }

                try
                {
                    bool ret = true;
                    if (ref_set.type == XML_DATA_TYPE_NAME.ENUM)
                    {
                        ret = _enumCsharpProcess(ref_set, enum_sb);
                    }
                    else
                    {
                        ret = _baseElementCsharpProcess(ref_set as XmlBaseRefer, class_sb);
                    }
                    if (!ret) return ret;
                }
                catch (Exception e)
                {
                    Reporter.PushError("输出Csharp代码失败！ {0}", e);
                    return false;
                }
            }

            for (int i = 0; i < lib.class_config.Count; i++)
            {
                XmlClassSet cs = lib.class_config[i];
                if(cs.mode == JSON_MODE.SERVER) {
                    continue;
                }
                try
                {
                    bool ret = _baseElementCsharpProcess(cs, class_sb);
                    if (!ret) return false;

                    m_classList.Add(cs);
                }
                catch (Exception e)
                {
                    Reporter.PushError("输出Csharp代码失败！ {0}", e);
                    return false;
                }
            }

            cs_sb.Append(enum_sb.ToString());
            cs_sb.Append(class_sb.ToString());

            string file_name = string.Format("tb_{0}{1}", lib.lib_name, FILE_EXT.CSHAPR);
            string filepath = Path.Combine(FILE_PATH.CS_WORKING_DIR, file_name);
            Console.WriteLine("输出【C#解析代码】 : {0}", filepath);
            WriteText(filepath, cs_sb.ToString());
            return true;
        }
        #endregion
        List<XmlClassSet> m_classList;
        #region metatable_id生成
        bool genMetaTableIdFile() {
            StringBuilder sb = new StringBuilder();
            int file_indent = 0;
            FormatHelper.CodeContent(sb, "public enum E_METATABLE_ID{", file_indent++);
            FormatHelper.CodeContent(sb, "MT_ID_START = 0,\n", file_indent);
            for (int i = 0; i < m_classList.Count; i++)
            {
                XmlClassSet cs = m_classList[i];
                string tail_content = string.Empty; 
                if (i == 0)
                {
                    tail_content = " = MT_ID_START,";
                }
                else
                {
                    tail_content = ",";
                }
                FormatHelper.CodeContent(sb, string.Format("MT_ID_{0}_{1}{2}", cs.ParentLib.lib_name.ToUpper(), cs.name.ToUpper(), tail_content), file_indent);
            }
            FormatHelper.CodeContent(sb, "", file_indent);
            FormatHelper.CodeContent(sb, "MT_ID_END,", file_indent);
            FormatHelper.CodeRightBracket(sb, ref file_indent);

            WriteText(Path.Combine(FILE_PATH.CS_WORKING_DIR, string.Format("{0}{1}", FILE_PATH.CS_METATABLE_DEFINE, FILE_EXT.CSHAPR)), sb.ToString());
            return true;
        }
        #endregion

        bool CSharpConverter()
        {
            
            foreach (var common_lib in m_allCommonLibs)
            {
                if (!processOneLib(common_lib)) return false;
            }

            m_classList = new List<XmlClassSet>();
            foreach (var lib_it in m_allLib)
            {
                if (!processOneLib(lib_it.Value)) return false;
            }

            genMetaTableIdFile();

            return true;
        }
    }
}
